#include <pthread.h>
#include <functional>
#include <string>
#include "Sock.hpp"
#include "log.hpp"

using func_t = std::function<std::string(std::string&)>;

static const uint16_t default_port = 8888;


namespace httpserver_ns
{
    class HttpServer;

    struct ThreadDate
    {
        ThreadDate(const int &sock, uint16_t &port, const std::string &ip, HttpServer *serv)
            : _sock(sock), _port(port), _ip(ip), _serv(serv)
        {
        }

        int _sock;
        uint16_t _port;
        std::string _ip;
        HttpServer *_serv;
    };


    class HttpServer
    {
    public:
        HttpServer(func_t func, const uint16_t& port = default_port)
            : _port(port), _func(func)
        {}

        void InitServer()
        {
            _sock.Socket();
            _sock.Bind(_port);
            _sock.Listen();
        }

        void Start()
        {
            while(true)
            {
                uint16_t client_port;
                std::string client_ip;

                int sock = _sock.Accept(&client_ip, &client_port);
                if(sock < 0) continue; // 如果未接收成功，继续寻找下一个

                ThreadDate* data = new ThreadDate(sock, client_port, client_ip, this);
                pthread_t th;
                pthread_create(&th, nullptr, ThreadRoute, data);
            }
        }

        void Service(const int sock)
        {
            char buffer[1024];
            std::string request;
            ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0);
            if(n > 0)
            {
                buffer[n] = 0;
                // 请求和响应都是字符串
                request = buffer;
                std::string response = _func(request);

                send(sock, response.c_str(), response.size(), 0);
            }
            else
            {
                LogMessage(Info, "User quit...");
            }
        }

        static void* ThreadRoute(void* args)
        {
            pthread_detach(pthread_self());
            ThreadDate* data = static_cast<ThreadDate*>(args);
            
            data->_serv->Service(data->_sock);
            close(data->_sock);
            delete data;
            return nullptr;
        }

        ~HttpServer()
        {}
    private:
        Sock _sock;
        func_t _func;
        uint16_t _port;
    };
}